﻿using HenuAlbum.ControllerModels;
using HenuAlbum.DbContext;
using HenuAlbum.Identity;
using HenuAlbum.Models;
using HenuAlbum.ResponseModels;
using HenuAlbum.Utils;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Serilog;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace HenuAlbum.Controllers
{

    [ApiController]
    [Route("api/[controller]")]
    public class AccountController : ControllerBase
    {
        private readonly UserManager<User> _userManager;
        private readonly RoleManager<Role> _roleManager;
        private readonly SignInManager<User> _signinManager;
        private readonly AppDbContext _appDbContext;

        public AccountController(UserManager<User> userManager,
                                 RoleManager<Role> roleManager,
                                 SignInManager<User> signInManager,
                                 AppDbContext appDbContext)
        {
            _userManager = userManager;
            _roleManager = roleManager;
            _signinManager = signInManager;
            _appDbContext = appDbContext;
        }
        [HttpPost("Register")]
        [Authorize(Roles = "管理员")]
        public async Task<IActionResult> RegisterAsync(RegisterAccount account)
        {
            var existingUser = await _userManager.FindByNameAsync(account.Username);

            if (existingUser != null)
            {
                return BadRequest(new AlreadyExistsError("用户已经存在."));
            }

            var user = new User
            {
                UserName = account.Username
            };

            var result = await _userManager.CreateAsync(user, account.Password);

            if (result.Succeeded)
            {
                await _userManager.AddToRoleAsync(user, "学生");
                return Ok(new OkResponse("注册成功!") { Data = new { user.Id, user.UserName } });
            }

            if (result.Errors.Any())
            {
                return BadRequest(new UnknownError(result.Errors.First().Description));
            }
            else
            {
                return BadRequest(new UnknownError());
            }

        }

        [HttpPost("Login")]
        public async Task<IActionResult> LoginAsync(LoginAccount account)
        {
            var user = await _userManager.FindByNameAsync(account.Username);
            if (user == null)
            {
                return BadRequest(new NotExistsError("用户不存在."));
            }

            var isCorrect = await _userManager.CheckPasswordAsync(user, account.Password);
            if (isCorrect)
            {
                if (user.IsLocked)
                {
                    return BadRequest(new IncorrectError("账号已被锁定，请联系管理员!"));
                }
                await _signinManager.SignInAsync(user, account.IsPersistent);
                Log.Information("用户: {username}({id}) 登录成功.", user.UserName, user.Id);
                return Ok(new OkResponse("登录成功") { Data = new { user.UserName, user.Id } });
            }
            else
            {
                return BadRequest(new IncorrectError("密码不正确."));
            }
        }

        [Authorize]
        [Authorize(Roles = "管理员")]
        [HttpPost("CreateRole")]
        public async Task<IActionResult> CreateRoleAsync(CreateRole role)
        {
            var hasExist = await _roleManager.RoleExistsAsync(role.Name);
            if (hasExist)
            {
                return BadRequest(new AlreadyExistsError("角色已存在."));
            }

            var newRole = new Role()
            {
                Name = role.Name
            };
            var result = await _roleManager.CreateAsync(newRole);

            if (result.Succeeded)
            {
                return Ok(new OkResponse("角色创建成功."));
            }

            if (result.Errors.Any())
            {
                return BadRequest(new UnknownError(result.Errors.First().Description));
            }
            else
            {
                return BadRequest(new UnknownError());
            }
        }

        [Authorize]
        [Authorize(Roles = "管理员")]
        [HttpPost("AssignRole")]
        public async Task<IActionResult> AssignRoleAsync(AssignRole param)
        {
            bool exist = await _roleManager.RoleExistsAsync(param.Role);
            if (!exist)
            {
                return BadRequest(new NotExistsError("角色不存在."));
            }

            var user = await _userManager.FindByNameAsync(param.Username);
            if (user == null)
            {
                return BadRequest(new NotExistsError("用户不存在."));
            }

            // 加入新角色
            var result_add = await _userManager.AddToRoleAsync(user, param.Role);

            if (result_add.Succeeded)
            {
                return Ok(new OkResponse("指派角色成功."));
            }
            else
            {
                return BadRequest(new UnknownError(result_add.Errors.FirstOrDefault().Description));
            }
        }

        [Authorize]
        [HttpGet("Logout")]
        public async Task<IActionResult> Logout()
        {
            var user = await _userManager.GetUserAsync(User);
            await _userManager.UpdateSecurityStampAsync(user);
            await _signinManager.SignOutAsync();
            return Ok(new OkResponse("成功."));
        }

        [Authorize]
        [HttpGet]
        public async Task<IActionResult> UserInfo()
        {
            var userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
            var user = await _appDbContext.Users
                .AsNoTracking()
                .Include(x => x.ManagedMajors)
                .Include(x => x.Class)
                .ThenInclude(x => x.Grade)
                .Include(x => x.Class)
                .ThenInclude(x => x.Major)
                .ThenInclude(x => x.College)
                .Where(x => x.Id == userId)
                .FirstOrDefaultAsync();
            var roles = await _userManager.GetRolesAsync(user);
            return Ok(new OkResponse()
            {
                Data =
                new
                {
                    user.UserName,
                    user.FullName,
                    user.Id,
                    Roles = roles,
                    ManagedMajors = user.ManagedMajors.Select(x => new { x.Id, x.Name }),
                    Class = user.Class == null ? null : new { user.Class.Id, user.Class.Name },
                    Grade = user.Class == null ? null : new { user.Class.Grade.Id, user.Class.Grade.Value, user.Class.Grade.Display },
                    Major = user.Class?.Major == null ? null : new { user.Class.Major.Id, user.Class.Major.Name },
                    College = user.Class?.Major?.College == null ? null : new { user.Class.Major.College.Id, user.Class.Major.College.Name }
                }
            });
        }

        [Authorize]
        [HttpGet("{id:int}")]
        public async Task<IActionResult> UserInfo(int id)
        {
            var user = await _appDbContext.Users
                .AsNoTracking()
                .Include(x => x.ManagedMajors)
                .Include(x => x.Class)
                .ThenInclude(x => x.Grade)
                .Include(x => x.Class)
                .ThenInclude(x => x.Major)
                .ThenInclude(x => x.College)
                .Where(x => x.Id == id)
                .FirstOrDefaultAsync();
            if (user == null)
            {
                return BadRequest(new NotExistsError("用户Id不存在."));
            }
            var roles = await _userManager.GetRolesAsync(user);
            return Ok(new OkResponse()
            {
                Data =
                new
                {
                    user.UserName,
                    user.FullName,
                    user.Id,
                    user.IsLocked,
                    Roles = roles,
                    ManagedMajors = user.ManagedMajors.Select(x => new { x.Id, x.Name }),
                    Class = user.Class == null ? null : new { user.Class.Id, user.Class.Name },
                    Grade = user.Class == null ? null : new { user.Class.Grade.Id, user.Class.Grade.Value, user.Class.Grade.Display },
                    Major = user.Class?.Major == null ? null : new { user.Class.Major.Id, user.Class.Major.Name },
                    College = user.Class?.Major?.College == null ? null : new { user.Class.Major.College.Id, user.Class.Major.College.Name }
                }
            });
        }

        [Authorize]
        [HttpGet("GetUserInfoByName")]
        [Authorize(Roles = "管理员")]
        public async Task<IActionResult> GetUserInfoByName(string username)
        {
            var user = await _appDbContext.Users
                .AsNoTracking()
                 .Include(x => x.ManagedMajors)
                .Include(x => x.Class)
                .ThenInclude(x => x.Grade)
                .Include(x => x.Class)
                .ThenInclude(x => x.Major)
                .ThenInclude(x => x.College)
                .Where(x => x.UserName == username)
                .FirstOrDefaultAsync();
            if (user == null)
            {
                return BadRequest(new NotExistsError("用户Id不存在."));
            }
            var roles = await _userManager.GetRolesAsync(user);
            return Ok(new OkResponse()
            {
                Data =
                new
                {
                    user.UserName,
                    user.FullName,
                    user.Id,
                    user.IsLocked,
                    Roles = roles,
                    ManagedMajors = user.ManagedMajors.Select(x => new { x.Id, x.Name }),
                    Class = user.Class == null ? null : new { user.Class.Id, user.Class.Name },
                    Grade = user.Class == null ? null : new { user.Class.Grade.Id, user.Class.Grade.Value, user.Class.Grade.Display },
                    Major = user.Class?.Major == null ? null : new { user.Class.Major.Id, user.Class.Major.Name },
                    College = user.Class?.Major?.College == null ? null : new { user.Class.Major.College.Id, user.Class.Major.College.Name }
                }
            });
        }

        [Authorize]
        [Authorize(Roles = "管理员")]
        [HttpPost("{id:int}/Lock")]
        public async Task<IActionResult> Lock(int id)
        {
            var user = await _userManager.FindByIdAsync(id.ToString());
            if (user == null)
            {
                return BadRequest(new NotExistsError("用户Id不存在."));
            }
            if (user.UserName == "root")
            {
                return BadRequest(new IncorrectError("锁定失败!"));
            }
            user.IsLocked = true;
            await _userManager.UpdateAsync(user);
            return Ok(new OkResponse());
        }

        [Authorize]
        [Authorize(Roles = "管理员")]
        [HttpPost("{id:int}/Unlock")]
        public async Task<IActionResult> Unlock(int id)
        {
            var user = await _userManager.FindByIdAsync(id.ToString());
            if (user == null)
            {
                return BadRequest(new NotExistsError("用户Id不存在."));
            }
            user.IsLocked = false;
            await _userManager.UpdateAsync(user);
            return Ok(new OkResponse());
        }

        [Authorize]
        [HttpPost("UpdateStudentInfo")]
        public async Task<IActionResult> UpdateStudentInfo(UpdateStudentInfo param)
        {
            var user = await _userManager.GetUserAsync(this.User);
            var roles = await _userManager.GetRolesAsync(user);

            // 如果指定了被修改信息的用户，而且对象不是自己，那么需要管理员权限
            if (param.UserId != null && param.UserId != user.Id)
            {
                if (!roles.Contains("管理员"))
                {
                    return BadRequest(new ActionNotAllowedError("没有权限"));
                }
                user = await _userManager.FindByIdAsync(param.UserId.ToString());
                if (user == null) return BadRequest(new NotExistsError("用户不存在"));
            }
            if (!_appDbContext.Classes.Any(x => x.Id == param.ClassId))
            {
                return BadRequest(new NotExistsError("班级不存在"));
            }
            user.ClassId = param.ClassId;

            // 用户创建的个人相册的班级也要修改
            _ = await _appDbContext.Database
                .ExecuteSqlRawAsync("Update Albums Set PersonalAlbum_ClassId = {0} Where Discriminator = 'PersonalAlbum' And CreatorId = {1};", param.ClassId, user.Id);
            // 下面的方法可能效率不高
            //var albums = await _appDbContext.PersonalAlbums.Where(x => x.CreatorId == user.Id).ToListAsync();
            //foreach(var album in albums)
            //{
            //    album.ClassId = param.ClassId;
            //}
            await _appDbContext.SaveChangesAsync();
            await _userManager.UpdateAsync(user);
            return Ok(new OkResponse());
        }

        [Authorize(Roles = "管理员")]
        [HttpPost("RemoveRoles")]
        public async Task<IActionResult> RemoveRoles(RemoveRoleOperator param)
        {
            var user = await _userManager.FindByIdAsync(param.Id.ToString());
            var roles = await _userManager.GetRolesAsync(user);
            if (null == user) return BadRequest(new IncorrectError("用户不存在"));
            if (0 == roles.Count) return BadRequest(new IncorrectError("该用户不存在任何角色身份！"));
            if (param.Mode == RemoveRole.RemoveAll)
            {
                await _userManager.RemoveFromRolesAsync(user, roles);
                return Ok(new OkResponse());
            }
            else if (param.Mode == RemoveRole.RemoveAdmin && roles.Contains("管理员"))
            {
                await _userManager.RemoveFromRoleAsync(user, "管理员");
                return Ok(new OkResponse());
            }
            else if (param.Mode == RemoveRole.RemoveInstructor && roles.Contains("辅导员"))
            {

                await _userManager.RemoveFromRoleAsync(user, "辅导员");
                return Ok(new OkResponse());
            }
            else
            {
                return BadRequest(new IncorrectError("该用户未被指派目标角色"));
            }

        }

        [HttpGet("Menus")]
        public IActionResult Menus()
        {
            string filename = "guest.json";
            do
            {
                if (User.IsInRole("管理员"))
                {
                    filename = "admin.json";
                    break;
                }
                else if (User.IsInRole("辅导员"))
                {
                    filename = "fdy.json";
                    break;
                }
                else if (User.IsInRole("学生"))
                {
                    filename = "student.json";
                    break;
                }
            } while (false);
            FileStream fileStream = System.IO.File.OpenRead(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "menus", filename));
            return File(fileStream, "application/json; charset=utf-8");
        }
        [HttpPost("Instructor/Create")]
        [Authorize(Roles = "管理员")]
        public async Task<IActionResult> GenerateInsAccount(CreateInstructorParam account)
        {
            var existingUser = await _userManager.FindByNameAsync(account.Username);

            if (existingUser != null)
            {
                return BadRequest(new AlreadyExistsError("用户已经存在."));
            }


            var major = await _appDbContext.Majors.Where(x => x.Id == account.ManagedMajorId).FirstOrDefaultAsync();
            if (null == major) return BadRequest(new IncorrectError("分配的专业不存在"));
            var user = new User
            {
                UserName = account.Username,
                FullName = account.FullName
            };
            await _userManager.CreateAsync(user, account.Password);
            user.ManagedMajors.Add(major);
            var result = await _userManager.AddToRoleAsync(user, "辅导员");
            if (result.Succeeded)
            {

                return Ok(new OkResponse("注册成功!") { Data = new { user.Id, account.FullName, user.UserName, role = "辅导员", ManagedMajoy = user.ManagedMajors.FirstOrDefault().Id } });
            }

            if (result.Errors.Any())
            {
                return BadRequest(new UnknownError(result.Errors.First().Description));
            }
            else
            {
                return BadRequest(new UnknownError());
            }
        }
        [HttpPost("PassWord/Change")]
        [Authorize]
        public async Task<IActionResult> PasswordChange(PassWordChangeParam param)
        {
            var user = await _userManager.GetUserAsync(User);
            var result = await _userManager.ChangePasswordAsync(user, param.CurrentPassword, param.NewPassword);
            if (result.Succeeded)
                return Ok(new OkResponse());
            else
                return BadRequest(new IncorrectError(result.Errors.FirstOrDefault().Description));
        }
        [HttpPost("PassWord/Reset")]
        [Authorize(Roles = "管理员")]
        public async Task<IActionResult> PassWordReset(PasswordResetParam param)
        {

            var user = await _userManager.FindByIdAsync(param.Id.ToString());
            if (null == user)
            {
                return BadRequest(new IncorrectError("用户不存在"));
            }
            await _userManager.RemovePasswordAsync(user);
            var result = await _userManager.AddPasswordAsync(user, param.NewPassword);
            if (result.Succeeded)
            {
                return Ok(new OkResponse());
            }
            else
            {
                return BadRequest(new IncorrectError(result.Errors.FirstOrDefault().Description));
            }
        }

        [HttpPost("AddManagedMajor")]
        [Authorize]
        [Authorize(Roles = "管理员")]
        public async Task<IActionResult> AddManagedMajoys(ManagedMajoyParam param)
        {
            var user = await _appDbContext.Users
                .Include(x => x.ManagedMajors)
                .Where(x => x.Id == param.UserId)
                .FirstOrDefaultAsync();
            if (user == null)
            {
                return BadRequest(new NotExistsError("用户不存在!"));
            }
            if (!await _userManager.IsInRoleAsync(user, "辅导员"))
            {
                return BadRequest(new NotExistsError("该辅导员不存在!"));
            }
            var major = await _appDbContext.Majors.AsNoTracking().Where(x => x.Id == param.MajorId).FirstOrDefaultAsync();
            if (major == null)
            {
                return BadRequest(new NotExistsError("专业不存在！"));
            }
            if (user.ManagedMajors.Any(x => x.Id == param.MajorId))
            {
                return BadRequest(new AlreadyExistsError("已分配该专业！"));
            }
            user.ManagedMajors.Add(major);
            await _userManager.UpdateAsync(user);
            return Ok(new OkResponse());
        }

        [HttpPost("DeleteManagedMajor")]
        [Authorize(Roles = "管理员")]
        public async Task<IActionResult> DeleteManagedMajor(ManagedMajoyParam param)
        {
            var user = await _appDbContext.Users
                .Include(x => x.ManagedMajors)
                .Where(x => x.Id == param.UserId)
                .FirstOrDefaultAsync();
            if (user.ManagedMajors.RemoveAll(x => x.Id == param.MajorId) == 0)
            {
                return BadRequest(new UnknownError("删除失败!"));
            }
            await _userManager.UpdateAsync(user);
            return Ok(new OkResponse());
        }

        [Authorize]
        [Authorize(Roles = "管理员,辅导员")]
        [HttpGet("QueryUsers")]
        public async Task<IActionResult> QueryUsers(string role, int limit = 20, int page = 1,
                                                        int? classId = null, int? majorId = null, int? collegeId = null)
        {
            if (role == null)
            {
                return BadRequest(new IncorrectError("缺少参数!"));
            }
            Tools.ResolveLimitAndPage(ref limit, ref page, 20, 100);
            var role_ = await _roleManager.FindByNameAsync(role);
            if (role_ == null)
            {
                return BadRequest(new NotExistsError("角色不存在！"));
            }
            var list = await _appDbContext.UserRoles
                .Include(x => x.User)
                .ThenInclude(x => x.ManagedMajors)
                .Include(x => x.User)
                .ThenInclude(x => x.Class)
                .ThenInclude(x => x.Grade)
                .Include(x => x.User)
                .ThenInclude(x => x.Class)
                .ThenInclude(x => x.Major)
                .ThenInclude(x => x.College)
                .Where(x => x.RoleId == role_.Id
                       && (classId == null || x.User.ClassId == (int)classId)
                       && (majorId == null || x.User.Class.MajorId == (int)majorId)
                       && (collegeId == null || x.User.Class.Major.CollegeId == (int)collegeId))
                .Select(x => new
                {
                    x.User.UserName,
                    x.User.FullName,
                    x.User.Id,
                    ManagedMajors = x.User.ManagedMajors.Select(x => new { x.Id, x.Name }),
                    Class = x.User.Class == null ? null : new { x.User.Class.Id, x.User.Class.Name },
                    Grade = x.User.Class == null ? null : new { x.User.Class.Grade.Id, x.User.Class.Grade.Value, x.User.Class.Grade.Display },
                    Major = x.User.Class.Major == null ? null : new { x.User.Class.Major.Id, x.User.Class.Major.Name },
                    College = x.User.Class.Major.College == null ? null : new { x.User.Class.Major.College.Id, x.User.Class.Major.College.Name }
                })
                .OrderBy(x => x.Id)
                .Skip(limit * (page - 1))
                .Take(limit)
                .ToListAsync();
            return Ok(new ArrayResponse(list));
        }

        [HttpPost("{username}/LoginWithoutPasswd")]
        public async Task<IActionResult> LoginWithoutPasswd(string username)
        {
            IPAddress addr = System.Net.IPAddress.Parse(HttpContext.Connection.RemoteIpAddress.ToString());
            if (username == null) return BadRequest(new IncorrectError("访问出错了！"));
            if (addr == null) return BadRequest(new IncorrectError("访问出错了！"));
            if (System.Net.IPAddress.IsLoopback(addr))
            {
                var user = await _userManager.FindByNameAsync(username);
                if (user == null) return BadRequest(new IncorrectError("未注册"));
                await _signinManager.SignInAsync(user, true);
                return Ok(new OkResponse());
            }
            return BadRequest(new IncorrectError("访问出错了！"));

        }
        [HttpPost("RegisterWithFullName")]
        public async Task<IActionResult> RegistreWithFullName(RegisterAccountWithFullNameParam account)
        {
            IPAddress addr = System.Net.IPAddress.Parse(HttpContext.Connection.RemoteIpAddress.ToString());
            if (addr == null) return BadRequest(new IncorrectError("访问出错了！"));
            if (System.Net.IPAddress.IsLoopback(addr))
            {
                var existingUser = await _userManager.FindByNameAsync(account.Username);

                if (existingUser != null)
                {
                    return BadRequest(new AlreadyExistsError("用户已经存在."));
                }

                var user = new User
                {
                    UserName = account.Username,
                    FullName = account.FullName
                };

                var result = await _userManager.CreateAsync(user, account.Password);

                if (result.Succeeded)
                {
                    if (account.Username.Length == 8)
                        await _userManager.AddToRoleAsync(user, "老师");
                    else
                        await _userManager.AddToRoleAsync(user, "学生");
                    return Ok(new OkResponse("注册成功!") { Data = new { user.Id, user.UserName } });
                }

                if (result.Errors.Any())
                {
                    return BadRequest(new UnknownError(result.Errors.First().Description));
                }
                else
                {
                    return BadRequest(new UnknownError());
                }
            }
            return BadRequest(new IncorrectError("访问出错了！"));
        }
    }
}

